#pragma once

#include "my_defs.h"
#include "my_log.h"
#include "my_atomic.h"
#include "my_queue.h"

/**
 * 注意: 在如下场景中, 慎用my_buf_chain_dequeue.
 * - 首先创造一个buf, 将它添加到buf_chain, 之后在这个buf中添加数据.
 * - 如果使用buf_chain_dequeue, 它会将这个buf从chain中摘除.
 * - 后续继续向buf中添加数据, 此时从buf_chain中是拿不到数据的.
 */

typedef struct {
    my_atomic_int64_t               refer;
    char                            *data;
    int64_t                         size;
    unsigned                        aligned:1;
} my_buf_data_t;

my_buf_data_t *my_buf_data_alloc(int64_t size);
my_buf_data_t *my_buf_data_aligned_alloc(int64_t size);
void my_buf_data_free(my_buf_data_t *buf_data);
void my_buf_data_hold(my_buf_data_t *buf_data);

typedef struct {
    my_atomic_int64_t               refer;
    my_buf_data_t                   *data;
    char                            *data_end;  // end space in buf data
    char                            *start;     // start in buf data
    char                            *end;       // end in buf data
    char                            *pos;       // consumer pos
    my_queue_t                      queue;
} my_buf_t;

my_buf_t *my_buf_alloc(my_buf_data_t *buf_data, char *start, char *end);
my_buf_t *my_buf_alloc_ext(int64_t size);
my_buf_t *my_buf_aligned_alloc_ext(int64_t size);
void my_buf_free(my_buf_t *buf);
void my_buf_hold(my_buf_t *buf);
uint32_t my_buf_crc32(my_buf_t *buf);

typedef struct {
    my_queue_t                      head;
} my_buf_chain_t;

my_buf_chain_t *my_buf_chain_alloc();
void my_buf_chain_free();
void my_buf_chain_enqueue(my_buf_chain_t *chain, my_buf_t *buf);
my_buf_t *my_buf_chain_dequeue(my_buf_chain_t *chain);
void my_buf_chain_consume(my_buf_chain_t *chain, int64_t n);
void my_buf_chain_copy(my_buf_chain_t *dest, const my_buf_chain_t *src);
void my_buf_chain_copy_n(my_buf_chain_t *dest, const my_buf_chain_t *src, int64_t len);
my_buf_t *my_buf_chain_last(my_buf_chain_t *chain);
// return first readable buf
my_buf_t *my_buf_chain_first(my_buf_chain_t *chan);
// return next readable buf at the cur buf.
my_buf_t *my_buf_chain_next(my_buf_chain_t *chain, my_buf_t *cur);
int64_t my_buf_chain_total_bytes(my_buf_chain_t *chain);
uint32_t my_buf_chain_crc32(my_buf_chain_t *chain);
